﻿#region License
/* Copyright (C) 2009 Tim Coulter
 * 
 * This file is part of ExtremeML.
 * 
 * ExtremeML is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public
 * License, as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
 * the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
*/
#endregion

using System.Collections;
using System.Collections.Generic;

namespace ExtremeML.Core
{
	/// <summary>
	/// Serves as the generic base class for classes that maintain collections of wrapper objects.
	/// </summary>
	public abstract class WrapperCollection<TWrapped, TMember, TInner> : WrapperBase<TWrapped>, IEnumerable<TMember>, IWrapperCollection
		where TMember : ItemWrapper<TInner>
	{
		#region Housekeeping

		/// <summary>
		/// Initializes a new instance of the <see cref="WrapperCollection{TWrapped, TMember, TInner}"/> class.
		/// </summary>
		/// <param name="wrapped">A document content object from which to populate this instance.</param>
		/// <param name="parent">An <see cref="IContentWrapper"/> that represents the parent wrapper instance.</param>
		/// <param name="package">An <see cref="IContentWrapper"/> that represents the package wrapper instance.</param>
		protected WrapperCollection(
			TWrapped wrapped,
			IContentWrapper parent,
			IContentWrapper package)
			: base(wrapped, parent, package)
		{
		}

		#endregion
		#region Properties

		/// <summary>
		/// Gets the contained <see cref="List{TMember}"/> that represents a collection of content objects.
		/// </summary>
		protected List<TMember> Items { get; private set; }

		/// <summary>
		/// Gets the number of items in the collection.
		/// </summary>
		public int Count
		{
			get { return Items.Count; }
		}

		/// <summary>
		/// Gets a collection member by its zero-based index.
		/// </summary>
		public TMember this[int index]
		{
			get { return Items[index]; }
		}

		#endregion
		#region Overrides

		/// <summary>
		/// When overridden in a derived generated partial class,
		/// populates the derived instance using default values.
		/// </summary>
		protected override void OnInitializing()
		{
			base.OnInitializing();
			Items = new List<TMember>();
			Wrapped = default(TWrapped);
		}

		/// <summary>
		/// When overridden in a derived generated partial class, extracts data from the wrapped content
		/// object and uses it to populate the scalar and wrapper members of the derived class instance.
		/// </summary>
		/// <remarks>
		/// This method is called by the class constructor when the wrapped object is not <c>null</c>.
		/// </remarks>
		protected override void OnDecomposing()
		{
			base.OnDecomposing();
			Items = new List<TMember>();
		}

		/// <summary>
		/// Returns a value that indicates whether this instance wraps content that should be saved to the document.
		/// </summary>
		/// <returns><c>true</c> when the criteria defined by the base class are met or
		/// when the contained collection has members; otherwise, <c>false</c>.</returns>
		internal override bool IsPopulated()
		{
			return base.IsPopulated() || Items.Count > 0;
		}

		/// <summary>
		/// Returns collection members as <see cref="IContentWrapper"/> instances.
		/// </summary>
		protected override IEnumerable<IWrapper> GetWrapperMembers()
		{
			foreach (var item in Items)
			{
				yield return item;
			}

			foreach (var member in GetCustomWrapperMembers())
			{
				yield return member;
			}
		}

		/// <summary>
		/// Returns the zero-based index of the passed item in the contained collection.
		/// </summary>
		/// <param name="item">A collection member to search for.</param>
		/// <returns>The zero-based index of the matching item.</returns>
		internal int IndexOf(
			TMember item)
		{
			return Items.IndexOf(item);
		}

		#endregion
		#region Custom Life-Cycle Methods

		/// <summary>
		/// When overridden in a derived custom partial class, declares custom wrapper
		/// persistence code that will execute before generated persistence code.
		/// </summary>
		protected virtual void OnCustomRecomposing()
		{
		}

		/// <summary>
		/// When overridden in a derived custom partial class, declares custom wrapper
		/// persistence code that will execute after generated persistence code.
		/// </summary>
		protected virtual void OnCustomRecomposed()
		{
		}

		/// <summary>
		/// When overridden in a derived custom partial class, performs
		/// housekeeping before a collection member addition.
		/// </summary>
		protected virtual void OnCustomAdding(
			TMember member)
		{
		}

		/// <summary>
		/// When overridden in a derived custom partial class, performs
		/// housekeeping and validation of a requested deletion.
		/// </summary>
		protected virtual bool OnCustomRemoving(
			TMember member)
		{
			return true;
		}

		/// <summary>
		/// When overridden in a derived custom partial class, performs
		/// housekeeping after a deletion.
		/// </summary>
		protected virtual void OnCustomRemoved(
			TMember member)
		{
		}

		#endregion
		#region Content Management Methods

		/// <summary>
		/// Removes all the members from the collection.
		/// </summary>
		internal abstract void Clear();

		/// <summary>
		/// Removes the passed member from the collection and removes its wrapped object from the package.
		/// </summary>
		/// <param name="member">A <see cref="IContentWrapper"/> to remove.</param>
		internal abstract void Remove(IContentWrapper member);

		#endregion
		#region IEnumerable Implementation

		/// <summary>
		/// Implements interface <see cref="IEnumerable{TMember}"/>.
		/// </summary>
		public IEnumerator<TMember> GetEnumerator()
		{
			return Items.GetEnumerator();
		}

		/// <summary>
		/// Implements interface <see cref="IEnumerable"/>.
		/// </summary>
		IEnumerator IEnumerable.GetEnumerator()
		{
			return Items.GetEnumerator();
		}

		#endregion
		#region IWrapperCollection Implementation

		void IWrapperCollection.Remove(IContentWrapper member)
		{
			Remove(member);
		}

		void IWrapperCollection.Clear()
		{
			Clear();
		}

		#endregion
	}
}
